﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Linq;

namespace Acms.WebControls
{
    [ValidationProperty("SelectedValue")]
    [ToolboxData("<{0}:AcmsRadioButtonList runat=server></{0}:AcmsRadioButtonList>")]
    public class AcmsRadioButtonList : CompositeDataBoundControl, IPostBackDataHandler
    {
        public AcmsRadioButtonList()
            : base()
        {
            SelectedIndex = -1;
        }

        protected override void OnPreRender(EventArgs e)
        {
            Page.RegisterRequiresPostBack(this);
            base.OnPreRender(e);
        }
        /// <summary>
        /// Field from the datasource to use as label text for radio buttotn
        /// </summary>
        public string DataTextField { get; set; }
        public string DataTextFormat { get; set; }

        /// <summary>
        /// Field from the datasource to use as value for radio buttotn
        /// </summary>
        public string DataValueField { get; set; }
        public string DataValueFormat { get; set; }

        /// <summary>
        /// CssClass for Radio Button
        /// </summary>
        public string DataRadioButtonCssClassField { get; set; }
        public string DataRadioButtonCssClassFormat { get; set; }
        
        /// <summary>
        /// CssClass for Label
        /// </summary>
        public string DataLabelCssClassField { get; set; }
        public string DataLabelCssClassFormat { get; set; }
        
        /// <summary>
        /// Css Class Filed to use for the wrapper arounf both the radio button and label
        /// </summary>
        public string DataCssClassField { get; set; }
        public string DataCssClassFormat { get; set; }

        public Acms.WebControls.AcmsRadioButton.LabelPositions LabelPosition { get; set; }

        protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
        {
            this.Controls.Clear();

            IEnumerator data = null;
            if (dataBinding && dataSource == null)
                data = new object[0].GetEnumerator();
            else if (dataBinding)
                data = dataSource.GetEnumerator();
            else
                data = new object[TotalItems].GetEnumerator();
            
            while (data.MoveNext())
            {
                var item = new AcmsRadioButton();
                item.ID = string.Concat(this.ID, "_", this.Controls.Count);
                this.Controls.Add(item);

                if (dataBinding)
                {
                    item.SetDataSource(data.Current, this.Controls.Count - 1);
                }

                item.LabelPosition = this.LabelPosition;

                if(ItemCreated != null)
                    ItemCreated(this, new ItemEventArgs(){Item = item});
            }

            if (dataBinding)
            {
                TotalItems = this.Controls.Count;
                for(int i = 0; i < this.Controls.Count; i++)
                {
                    AcmsRadioButton item = this.Controls[i] as AcmsRadioButton;
                    item.GroupName = this.ClientID;

                    if (!string.IsNullOrEmpty(DataTextField))
                    {
                        item.Text = GetDataBoundValue(item.DataItem, DataTextField, DataTextFormat);
                    }

                    if (!string.IsNullOrEmpty(DataValueField))
                    {
                        item.Value = GetDataBoundValue(item.DataItem, DataTextField, DataTextFormat);
                    }
                    else if (!string.IsNullOrEmpty(DataTextField))
                    {
                        item.Value = GetDataBoundValue(item.DataItem, DataTextField, DataTextFormat);
                    }

                    if (!string.IsNullOrEmpty(DataRadioButtonCssClassField))
                    {
                        item.CssClass = GetDataBoundValue(item.DataItem, DataRadioButtonCssClassField, DataRadioButtonCssClassFormat);
                    }

                    if (!string.IsNullOrEmpty(DataRadioButtonCssClassField))
                    {
                        item.RadioButtonCssClass = GetDataBoundValue(item.DataItem, DataRadioButtonCssClassField, DataRadioButtonCssClassFormat);
                    }

                    if (!string.IsNullOrEmpty(DataLabelCssClassField))
                    {
                        item.LabelCssClass = GetDataBoundValue(item.DataItem, DataLabelCssClassField, DataLabelCssClassFormat);
                    }

                    if (!string.IsNullOrEmpty(DataCssClassField))
                    {
                        item.CssClass = GetDataBoundValue(item.DataItem, DataCssClassField, DataCssClassFormat);
                    }

                    if (item.Value == SelectedValue)
                    {
                        item.Checked = true;
                        SelectedIndex = i;
                    }
                    else
                    {
                        item.Checked = false;
                    }

                    item.DataBind();
                    if (ItemDataBound != null)
                        ItemDataBound(this, new ItemEventArgs() { Item = item });
                }
            }

            return TotalItems;
        }

        /*void tmp_CheckedChanged(object sender, EventArgs e)
        {
            AcmsRadioButton tmp = sender as AcmsRadioButton;
            if (tmp.Checked)
            {
                _SelectedValue = tmp.Value;
                SelectedIndex = tmp.DataItemIndex;
                if (SelectedIndexChanged != null)
                    SelectedIndexChanged(this, EventArgs.Empty);
            }
        }*/

        private int TotalItems { get; set; }
        private string _SelectedValue;
        public string SelectedValue
        {
            get
            {
                return _SelectedValue;
            }
            set
            {
                _SelectedValue = value;
                if (ChildControlsCreated)
                {
                    var uncheck = this.Controls.OfType<AcmsRadioButton>().Where(x => x.Value != _SelectedValue && x.Checked).FirstOrDefault();
                    if (uncheck != null)
                        uncheck.Checked = false;
                    var item = this.Controls.OfType<AcmsRadioButton>().Where(x => x.Value == _SelectedValue && !x.Checked).FirstOrDefault();
                    if (item != null)
                    {
                        item.Checked = true;
                        SelectedIndex = item.DataItemIndex;
                    }
                }
            }
        }

        public int SelectedIndex { get; private set; }

        protected override object SaveViewState()
        {
            ViewState["SelectedIndex"] = SelectedIndex;
            ViewState["SelectedValue"] = SelectedValue;
            ViewState["TotalItems"] = TotalItems;
            return base.SaveViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            SelectedValue = ViewState["SelectedValue"] as string;
            SelectedIndex = (int)ViewState["SelectedIndex"];
            TotalItems = (int)ViewState["TotalItems"];
        }

        private string GetDataBoundValue(object dataItem, string name, string format)
        {
            if (dataItem != null || string.IsNullOrEmpty(name))
            {
                if (string.IsNullOrEmpty(format))
                    format = "{0}";
                return DataBinder.Eval(dataItem, name, format);
            }
            else
            {
                return null;
            }
        }

        public event EventHandler SelectedIndexChanged;
        public event EventHandler<ItemEventArgs> ItemDataBound;
        public event EventHandler<ItemEventArgs> ItemCreated; 

        public AcmsRadioButton[] Items
        {
            get
            {
                if (ChildControlsCreated)
                {
                    return this.Controls.OfType<AcmsRadioButton>().ToArray();
                }
                else
                {
                    return null;
                }
            }
        }

        #region IPostBackDataHandler Members

        public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            var val = postCollection[this.ClientID];
            int index = SelectedIndex;
            //if null then nothing checked
            if (val == null)
            {
                index = -1;
            }
            else
            {
                try
                {
                    index = int.Parse(val);
                }
                catch (FormatException)
                {
                }
            }

            if (index == -1 && SelectedIndex != -1)
            {
                Items.Where(x => x.Checked).Select(x => x.Checked = false);
                this.SelectedIndex = -1;
                _SelectedValue = null;
                return true;
            }
            else if (this.SelectedIndex != index && index <= Items.Count() && index >= 0)
            {
                var uncheck = Items.Where(x => x.Checked);
                foreach (var item in uncheck)
                {
                    item.Checked = false;
                }
                this.SelectedIndex = index;
                Items.ElementAt(SelectedIndex).Checked = true;
                _SelectedValue = Items.ElementAt(SelectedIndex).Value;
                return true;
            }
            else
            {
                return false;
            }
        }

        public void RaisePostDataChangedEvent()
        {
            if (this.SelectedIndexChanged != null)
            {
                SelectedIndexChanged(this, EventArgs.Empty);
            }
        }

        #endregion

        public class ItemEventArgs : EventArgs
        {
            public AcmsRadioButton Item { get; internal set; }
        }
    }


    public class AcmsRadioButton : WebControl, IDataItemContainer, IPostBackDataHandler
    {
        public AcmsRadioButton()
        {
            DataItemIndex = -1;
        }

        internal void SetDataSource(object dataSource, int index)
        {
            this.DataItem = dataSource;
            this.DataItemIndex = index;
        }

        public enum LabelPositions { Before, After }
        public LabelPositions LabelPosition { get; set; }
        public string Text { get; set; }
        public string LabelCssClass { get; set; }
        public string RadioButtonCssClass { get; set; }
        public string Value { get; set; }
        public bool Checked { get; set; }
        public string GroupName { get; set; }

        protected override object SaveViewState()
        {
            ViewState["DataItemIndex"] = DataItemIndex;
            ViewState["Text"] = Text;
            ViewState["LabelCssClass"] = LabelCssClass;
            ViewState["RadioButtonCssClass"] = RadioButtonCssClass;
            ViewState["Value"] = Value;
            ViewState["Checked"] = Checked;
            ViewState["GroupName"] = GroupName;
            return base.SaveViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            if (ViewState["DataItemIndex"] is int)
                DataItemIndex = (int)ViewState["DataItemIndex"];
            Text = ViewState["Text"] as string;
            LabelCssClass = ViewState["LabelCssClass"] as string;
            RadioButtonCssClass = ViewState["RadioButtonCssClass"] as string;
            Value = ViewState["Value"] as string;
            if(ViewState["Checked"] is bool)
                Checked = (bool)ViewState["Checked"];
            GroupName = ViewState["GroupName"] as string;

        }

        protected override void OnPreRender(EventArgs e)
        {
            if (DataItemIndex == -1)
                Page.RegisterRequiresPostBack(this);
            base.OnPreRender(e);
        }

        protected override void  Render(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
            if (!string.IsNullOrEmpty(CssClass))
                writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
            writer.RenderBeginTag(HtmlTextWriterTag.Span);

            if (LabelPosition == LabelPositions.Before)
                RenderLabel(writer);
            RenderRadioButton(writer);
            if (LabelPosition == LabelPositions.After)
                RenderLabel(writer);

            writer.RenderEndTag();
        }

        private void RenderLabel(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Id, string.Concat(this.ClientID, "_label"));
            writer.AddAttribute(HtmlTextWriterAttribute.For, string.Concat(this.ClientID, "_radio"));
            if (!string.IsNullOrEmpty(LabelCssClass))
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.LabelCssClass);
            writer.RenderBeginTag(HtmlTextWriterTag.Label);
            writer.Write(this.Text);
            writer.RenderEndTag();
        }

        private void RenderRadioButton(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Id, string.Concat(this.ClientID, "_radio"));
            writer.AddAttribute(HtmlTextWriterAttribute.Name, this.GroupName);
            if (DataItemIndex == -1)
                writer.AddAttribute(HtmlTextWriterAttribute.Value, this.ID);
            else
                writer.AddAttribute(HtmlTextWriterAttribute.Value, this.DataItemIndex.ToString());
            if (!string.IsNullOrEmpty(RadioButtonCssClass))
                writer.AddAttribute(HtmlTextWriterAttribute.Class, this.RadioButtonCssClass);
            if (Checked)
                writer.AddAttribute(HtmlTextWriterAttribute.Checked, "true");
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "radio");
            writer.RenderBeginTag(HtmlTextWriterTag.Input);
            writer.RenderEndTag();
        }

        public object DataItem { get; private set; }
        public int DataItemIndex { get; private set; }
        public int DisplayIndex { get { return DataItemIndex; } }

        #region IPostBackDataHandler Members

        public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            var val = postCollection[GroupName];
            var tmp = Checked;
            if (!string.IsNullOrEmpty(val))
            {
                this.Checked = this.ID == val;
            }
            return tmp != this.Checked;
        }

        public void RaisePostDataChangedEvent()
        {
            if (CheckedChanged != null)
            {
                CheckedChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler CheckedChanged;

        #endregion
    }
}
